Udforsk WebAssembly host-bindinger til integration af WASM-moduler med kørselsmiljøer. Denne guide dækker fordele, use cases og praktisk implementering.
WebAssembly Host-bindinger: Problemfri Integration med Kørselsmiljøer
WebAssembly (WASM) har hurtigt udviklet sig fra en teknologi kun for browsere til en universel kørselsløsning. Dets løfte om høj ydeevne, portabilitet og sikkerhed gør det til et attraktivt valg for en bred vifte af applikationer, fra serverløse funktioner til indlejrede systemer. For at WASM virkelig kan frigøre sit potentiale, er det dog nødvendigt, at det interagerer problemfrit med værtsmiljøet – det program eller system, der kører WASM-modulet. Det er her, WebAssembly Host-bindinger spiller en afgørende rolle.
I denne omfattende guide vil vi dykke ned i finesserne ved WebAssembly host-bindinger, udforske hvad de er, hvorfor de er essentielle, og hvordan de muliggør robust integration mellem WASM-moduler og deres forskellige kørselsmiljøer. Vi vil undersøge forskellige tilgange, fremhæve virkelige anvendelsesscenarier og give handlingsorienterede indsigter for udviklere, der ønsker at udnytte denne kraftfulde funktion.
Forståelse af WebAssembly Host-bindinger
I sin kerne er WebAssembly designet som et portabelt kompileringsmål for programmeringssprog. WASM-moduler er i bund og grund selvstændige kodeenheder, der kan eksekveres i et sandboxed miljø. Denne sandbox giver sikkerhed som standard ved at begrænse, hvad WASM-kode kan gøre. De fleste praktiske applikationer kræver dog, at WASM-moduler interagerer med omverdenen – for at få adgang til systemressourcer, kommunikere med andre dele af applikationen eller udnytte eksisterende biblioteker.
Host-bindinger, også kendt som importerede funktioner eller værtsfunktioner, er mekanismen, hvormed et WASM-modul kan kalde funktioner, der er defineret og leveret af værtsmiljøet. Tænk på det som en kontrakt: WASM-modulet erklærer, at det har brug for, at visse funktioner er tilgængelige, og værtsmiljøet garanterer, at de bliver stillet til rådighed.
Omvendt kan værtsmiljøet også kalde funktioner, der er eksporteret af et WASM-modul. Denne tovejskommunikation er fundamental for enhver meningsfuld integration.
Hvorfor er Host-bindinger Essentielle?
- Interoperabilitet: Host-bindinger er broen, der tillader WASM-kode at interagere med værtssproget og dets økosystem. Uden dem ville WASM-moduler være isolerede og ude af stand til at udføre almindelige opgaver som at læse filer, lave netværksanmodninger eller interagere med brugergrænseflader.
- Udnyttelse af Eksisterende Funktionalitet: Udviklere kan skrive deres kerneforretningslogik i WASM (måske af hensyn til ydeevne eller portabilitet), mens de udnytter de enorme biblioteker og muligheder i deres værtsmiljø (f.eks. C++-biblioteker, Go's samtidighedsprimitiver eller JavaScripts DOM-manipulation).
- Sikkerhed og Kontrol: Værtsmiljøet dikterer, hvilke funktioner der eksponeres for WASM-modulet. Dette giver en finkornet kontrol over de kapabiliteter, der tildeles WASM-koden, hvilket forbedrer sikkerheden ved kun at eksponere nødvendige funktionaliteter.
- Ydeevneoptimeringer: For beregningsintensive opgaver kan det være yderst fordelagtigt at overføre dem til WASM. Disse opgaver skal dog ofte interagere med værten for I/O eller andre operationer. Host-bindinger faciliterer denne effektive dataudveksling og opgavedelegering.
- Portabilitet: Selvom WASM i sig selv er portabelt, kan måden, det interagerer med værtsmiljøet på, variere. Veldesignede host-binding-interfaces sigter mod at abstrahere disse værtsspecifikke detaljer væk, hvilket gør det lettere at genbruge WASM-moduler på tværs af forskellige kørselsmiljøer.
Almindelige Mønstre og Tilgange til Host-bindinger
Implementeringen af host-bindinger kan variere afhængigt af WebAssembly-kørselsmiljøet og de involverede sprog. Der er dog opstået flere almindelige mønstre:
1. Eksplicitte Funktionsimporter
Dette er den mest fundamentale tilgang. WASM-modulet lister eksplicit de funktioner, det forventer at importere fra værten. Værtsmiljøet leverer derefter implementeringer for disse importerede funktioner.
Eksempel: Et WASM-modul skrevet i Rust kan importere en funktion som console_log(message: *const u8, len: usize) fra værten. Værtens JavaScript-miljø ville så levere en funktion ved navn console_log, der tager en pointer og en længde, dereferencerer hukommelsen på den adresse og kalder JavaScripts console.log.
Nøgleaspekter:
- Typesikkerhed: Signaturen af den importerede funktion (navn, argumenttyper, returtyper) skal matche værtens implementering.
- Hukommelseshåndtering: Data, der sendes mellem WASM-modulet og værten, befinder sig ofte i WASM-modulets lineære hukommelse. Bindinger skal håndtere læsning fra og skrivning til denne hukommelse på en sikker måde.
2. Indirekte Funktionskald (Funktionspointers)
Ud over direkte funktionsimporter tillader WASM, at værten kan sende funktionspointers (eller referencer) som argumenter til WASM-funktioner. Dette giver WASM-kode mulighed for dynamisk at kalde funktioner leveret af værten under kørsel.
Eksempel: Et WASM-modul kan modtage en callback-funktionspointer til hændelseshåndtering. Når en hændelse sker inden i WASM-modulet, kan det kalde denne callback og sende relevante data tilbage til værten.
Nøgleaspekter:
- Fleksibilitet: Muliggør mere dynamiske og komplekse interaktioner end direkte importer.
- Overhead: Kan undertiden medføre en lille ydeevne-overhead sammenlignet med direkte kald.
3. WASI (WebAssembly System Interface)
WASI er et modulært systeminterface for WebAssembly, designet til at gøre det muligt for WASM at køre uden for browseren på en sikker og portabel måde. Det definerer et standardiseret sæt af API'er, som WASM-moduler kan importere, og dækker almindelige systemfunktionaliteter som fil-I/O, netværk, ure og generering af tilfældige tal.
Eksempel: I stedet for at importere brugerdefinerede funktioner til at læse filer, kan et WASM-modul importere funktioner som fd_read eller path_open fra wasi_snapshot_preview1-modulet. WASM-kørselsmiljøet leverer så implementeringen for disse WASI-funktioner, ofte ved at oversætte dem til native systemkald.
Nøgleaspekter:
- Standardisering: Sigter mod at levere et konsistent API på tværs af forskellige WASM-kørselsmiljøer og værtsmiljøer.
- Sikkerhed: WASI er designet med sikkerhed og kapabilitetsbaseret adgangskontrol for øje.
- Udviklende Økosystem: WASI er stadig under aktiv udvikling, med nye moduler og funktioner, der bliver tilføjet.
4. Kørselsmiljøspecifikke API'er og Biblioteker
Mange WebAssembly-kørselsmiljøer (som Wasmtime, Wasmer, WAMR, Wazero) leverer deres egne højere-niveau API'er og biblioteker for at forenkle oprettelsen og håndteringen af host-bindinger. Disse abstraherer ofte de lav-niveau detaljer ved WASM-hukommelseshåndtering og funktionssignatur-matching væk.
Eksempel: En Rust-udvikler, der bruger wasmtime-craten, kan bruge #[wasmtime_rust::async_trait]- og #[wasmtime_rust::component]-attributterne til at definere værtsfunktioner og komponenter med minimal boilerplate-kode. Tilsvarende giver wasmer-sdk i Rust eller wasmer-interface-types i forskellige sprog værktøjer til at definere interfaces og generere bindinger.
Nøgleaspekter:
- Udvikleroplevelse: Forbedrer brugervenligheden markant og reducerer sandsynligheden for fejl.
- Effektivitet: Ofte optimeret for ydeevne inden for deres specifikke kørselsmiljø.
- Leverandørbinding: Kan binde din implementering tættere til et bestemt kørselsmiljø.
Integration af WASM med Forskellige Værtsmiljøer
Kraften i WebAssembly host-bindinger er mest tydelig, når vi ser på, hvordan WASM kan integreres med forskellige værtsmiljøer. Lad os udforske nogle fremtrædende eksempler:
1. Webbrowsere (JavaScript som Vært)
Dette er WebAssemblys fødested. I browseren fungerer JavaScript som vært. WASM-moduler indlæses og instantieres ved hjælp af WebAssembly JavaScript API'et.
- Bindinger: JavaScript leverer importerede funktioner til WASM-modulet. Dette gøres ofte ved at oprette et
WebAssembly.Imports-objekt. - Dataudveksling: WASM-moduler har deres egen lineære hukommelse. JavaScript kan få adgang til denne hukommelse ved hjælp af
WebAssembly.Memory-objekter for at læse/skrive data. Biblioteker somwasm-bindgenautomatiserer den komplekse proces med at sende komplekse datatyper (strenge, objekter, arrays) mellem JavaScript og WASM. - Anvendelsesscenarier: Spiludvikling (Unity, Godot), multimediebehandling, beregningsintensive opgaver i webapplikationer, udskiftning af ydeevnekritiske JavaScript-moduler.
Globalt Eksempel: Forestil dig en webapplikation til fotoredigering. En beregningsintensiv billedfiltreringsalgoritme kunne skrives i C++ og kompileres til WASM. JavaScript ville indlæse WASM-modulet, levere en process_image-værtsfunktion, der tager billeddata (måske som et byte-array i WASM-hukommelsen), og derefter vise det behandlede billede tilbage til brugeren.
2. Server-side Kørselsmiljøer (f.eks. Node.js, Deno)
At køre WASM uden for browseren åbner op for et stort nyt landskab. Node.js og Deno er populære JavaScript-kørselsmiljøer, der kan hoste WASM-moduler.
- Bindinger: Ligesom i browsermiljøer kan JavaScript i Node.js eller Deno levere importerede funktioner. Kørselsmiljøer har ofte indbygget understøttelse eller moduler til indlæsning og interaktion med WASM.
- Adgang til Systemressourcer: WASM-moduler, der hostes på serveren, kan gives adgang til værtens filsystem, netværkssockets og andre systemressourcer via omhyggeligt udformede host-bindinger. WASI er særligt relevant her.
- Anvendelsesscenarier: Udvidelse af Node.js med højtydende moduler, kørsel af upålidelig kode sikkert, edge computing-implementeringer, mikroservices.
Globalt Eksempel: En global e-handelsplatform kan bruge Node.js til sin backend. For at håndtere betalingsbehandling sikkert og effektivt, kunne et kritisk modul skrives i Rust og kompileres til WASM. Dette WASM-modul ville importere funktioner fra Node.js for at interagere med et sikkert hardware-sikkerhedsmodul (HSM) eller for at udføre kryptografiske operationer, hvilket sikrer, at følsomme data aldrig forlader WASM-sandboxen eller håndteres af betroede værtsfunktioner.
3. Native Applikationer (f.eks. C++, Go, Rust)
WebAssembly-kørselsmiljøer som Wasmtime og Wasmer kan indlejres i native applikationer skrevet i sprog som C++, Go og Rust. Dette giver udviklere mulighed for at integrere WASM-moduler i eksisterende C++-applikationer, Go-tjenester eller Rust-daemons.
- Bindinger: Det indlejrende sprog leverer værtsfunktioner. Kørselsmiljøer tilbyder API'er til at definere disse funktioner og sende dem til WASM-instansen.
- Dataudveksling: Effektive dataoverførselsmekanismer er afgørende. Kørselsmiljøer giver måder at mappe WASM-hukommelse og kalde WASM-funktioner fra værtssproget, og omvendt.
- Anvendelsesscenarier: Pluginsystemer, sandboxing af upålidelig kode inden i en native applikation, kørsel af kode skrevet i et sprog inden i en applikation skrevet i et andet, serverløse platforme, indlejrede enheder.
Globalt Eksempel: Et stort multinationalt selskab, der udvikler en ny IoT-platform, kan bruge et Rust-baseret indlejret Linux-system. De kunne bruge WebAssembly til at implementere og opdatere logik på edge-enheder. Den centrale Rust-applikation ville fungere som vært og levere host-bindinger til WASM-moduler (kompileret fra forskellige sprog som Python eller Lua) til behandling af sensordata, enhedskontrol og lokal beslutningstagning. Dette giver fleksibilitet til at vælge det bedste sprog til specifikke enhedsopgaver, samtidig med at man opretholder et sikkert og opdaterbart kørselsmiljø.
4. Serverløs og Edge Computing
Serverløse platforme og edge computing-miljøer er oplagte kandidater til WebAssembly på grund af dets hurtige opstartstider, lille fodaftryk og sikkerhedsisolering.
- Bindinger: Serverløse platforme leverer typisk API'er til at interagere med deres tjenester (f.eks. databaser, meddelelseskøer, godkendelse). Disse eksponeres som importerede WASM-funktioner. WASI er ofte den underliggende mekanisme for disse integrationer.
- Anvendelsesscenarier: Kørsel af backend-logik uden at administrere servere, edge-funktioner til lav-latens databehandling, logik i content delivery network (CDN), IoT-enhedshåndtering.
Globalt Eksempel: En global streamingtjeneste kunne bruge WASM-baserede funktioner på edge'en til at personalisere indholdsanbefalinger baseret på brugerens placering og visningshistorik. Disse edge-funktioner, hostet på CDN-servere verden over, ville importere bindinger for at få adgang til cachede brugerdata og interagere med en anbefalingsmotor-API, alt imens de nyder godt af WASM's hurtige koldstarter og minimale ressourceforbrug.
Praktisk Implementering: Casestudier og Eksempler
Lad os se på, hvordan host-bindinger implementeres i praksis ved hjælp af populære kørselsmiljøer og sprogkombinationer.
Casestudie 1: Rust WASM-modul, der Kalder JavaScript-funktioner
Dette er et almindeligt scenarie for webudvikling. wasm-bindgen-værktøjskæden er afgørende her.
Rust-kode (i din .rs-fil):
// Declare the function we expect from JavaScript
#[wasm_bindgen]
extern "C" {
fn alert(s: &str);
}
#[wasm_bindgen]
pub fn greet(name: &str) {
alert(&format!("Hello, {}!", name));
}
JavaScript-kode (i din HTML- eller .js-fil):
// Import the WASM module
import init, { greet } from './pkg/my_wasm_module.js';
async function run() {
await init(); // Initialize WASM module
greet("World"); // Call the exported WASM function
}
run();
Forklaring:
extern "C"-blokken i Rust erklærer funktioner, der vil blive importeret fra værten.#[wasm_bindgen]bruges til at markere disse og andre funktioner for problemfri interoperabilitet.wasm-bindgengenererer den nødvendige JavaScript-limkode og håndterer den komplekse data-marshalling mellem Rust (kompileret til WASM) og JavaScript.
Casestudie 2: Go-applikation, der Hoster et WASM-modul med WASI
Brug af wasi_ext (eller lignende) Go-pakke med et WASM-kørselsmiljø som Wasmtime.
Go Værtskode:
package main
import (
"fmt"
"os"
"github.com/bytecodealliance/wasmtime-go"
)
func main() {
// Create a new runtime linker
linker := wasmtime.NewLinker(wasmtime.NewStore(nil))
// Define WASI preview1 capabilities (e.g., stdio, clocks)
wasiConfig := wasmtime.NewWasiConfig()
wasiConfig.SetStdout(os.Stdout)
wasiConfig.SetStderr(os.Stderr)
// Create a WASI instance bound to the linker
wasi, _ := wasmtime.NewWasi(linker, wasiConfig)
// Load WASM module from file
module, _ := wasmtime.NewModuleFromFile(linker.GetStore(), "my_module.wasm")
// Instantiate the WASM module
instance, _ := linker.Instantiate(module)
// Get the WASI export (usually `_start` or `main`)
// The actual entry point depends on how the WASM was compiled
entryPoint, _ := instance.GetFunc("my_entry_point") // Example entry point
// Call the WASM entry point
if entryPoint != nil {
entryPoint.Call()
} else {
fmt.Println("Entry point function not found.")
}
// Clean up WASI resources
wasi.Close()
}
WASM-modul (f.eks. kompileret fra C/Rust med WASI-target):
WASM-modulet ville simpelthen bruge standard WASI-kald, som at printe til standard output:
// Example in C compiled with --target=wasm32-wasi
#include <stdio.h>
int main() {
printf("Hello from WebAssembly WASI module!\n");
return 0;
}
Forklaring:
- Go-værten opretter en Wasmtime store og linker.
- Den konfigurerer WASI-kapabiliteter og mapper standard output/error til Go's fil-deskriptorer.
- WASM-modulet indlæses og instantieres, med WASI-funktioner importeret og leveret af linkeren.
- Go-programmet kalder derefter en eksporteret funktion i WASM-modulet, som igen bruger WASI-funktioner (som
fd_write) til at producere output.
Casestudie 3: C++-applikation, der Hoster WASM med Brugerdefinerede Bindinger
Brug af et kørselsmiljø som Wasmer-C-API eller Wasmtime's C API.
C++ Værtskode (konceptuelt eksempel med Wasmer C API):
#include <wasmer.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Custom host function implementation
void my_host_log(int message_ptr, int message_len) {
// Need to access WASM memory here to get the string
// This requires managing the WASM instance's memory
printf("[HOST LOG]: "
"%.*s\n",
message_len, // Assuming message_len is correct
wasm_instance_memory_buffer(instance, message_ptr, message_len)); // Hypothetical memory access function
}
int main() {
// Initialize Wasmer
wasmer_engine_t* engine = wasmer_engine_new();
wasmer_store_t* store = wasmer_store_new(engine);
// Create a Wasmtime linker or Wasmer Imports object
wasmer_imports_t* imports = wasmer_imports_new();
// Define the host function signature
wasmer_func_type_t* func_type = wasmer_func_type_new(
(wasmer_value_kind_t[]) { WASMER_VALUE_I32 }, // Param 1: pointer (i32)
1,
(wasmer_value_kind_t[]) { WASMER_VALUE_I32 }, // Param 2: length (i32)
1,
(wasmer_value_kind_t[]) { WASMER_VALUE_VOID }, // Return type: void
0
);
// Create a callable host function
wasmer_func_t* host_func = wasmer_func_new(store, func_type, my_host_log);
// Add the host function to the imports object
wasmer_imports_define(imports, "env", "log", host_func);
// Compile and instantiate the WASM module
wasmer_module_t* module = NULL;
wasmer_instance_t* instance = NULL;
// ... load "my_module.wasm" ...
// ... instantiate instance using store and imports ...
// Get and call an exported WASM function
wasmer_export_t* export = wasmer_instance_exports_get_index(instance, 0); // Assuming first export is our target
wasmer_value_t* result = NULL;
wasmer_call(export->func, &result);
// ... handle result and clean up ...
wasmer_imports_destroy(imports);
wasmer_store_destroy(store);
wasmer_engine_destroy(engine);
return 0;
}
WASM-modul (kompileret fra C/Rust med en funktion ved navn `log`):
// Example in C:
extern void log(int message_ptr, int message_len);
void my_wasm_function() {
const char* message = "This is from WASM!";
// Need to write message to WASM linear memory and get its pointer/length
// For simplicity, assume memory management is handled.
int msg_ptr = /* get pointer to message in WASM memory */;
int msg_len = /* get length of message */;
log(msg_ptr, msg_len);
}
Forklaring:
- C++-værten definerer en native funktion (
my_host_log), der vil være kaldbar fra WASM. - Den definerer den forventede signatur for denne værtsfunktion.
- En
wasmer_func_toprettes fra den native funktion og signaturen. - Denne
wasmer_func_ttilføjes til et importobjekt under et specifikt modulnavn (f.eks. "env") og funktionsnavn (f.eks. "log"). - Når WASM-modulet instantieres, importerer det "env"'s "log"-funktion.
- Når WASM-koden kalder
log, sender Wasmer-kørselsmiljøet kaldet videre til C++-funktionenmy_host_logog passerer omhyggeligt hukommelsespointers og længder.
Udfordringer og Bedste Praksis
Selvom host-bindinger tilbyder enorm kraft, er der udfordringer, man skal overveje:
Udfordringer:
- Kompleksiteten af Data-marshalling: At sende komplekse datastrukturer (strenge, arrays, objekter, brugerdefinerede typer) mellem WASM og værten kan være kompliceret, især håndtering af hukommelsesejerskab og levetider.
- Ydeevne-overhead: Hyppige eller ineffektive kald mellem WASM og værten kan introducere ydeevneflaskehalse på grund af kontekstskift og datakopiering.
- Værktøjer og Fejlfinding: Fejlfinding af interaktioner mellem WASM og værten kan være mere udfordrende end fejlfinding inden for et enkelt sprogmiljø.
- API-stabilitet: Selvom WebAssembly i sig selv er stabilt, kan host-binding-mekanismer og kørselsmiljøspecifikke API'er udvikle sig, hvilket potentielt kan kræve kodeopdateringer. WASI sigter mod at afbøde dette for systeminterfaces.
- Sikkerhedsovervejelser: At eksponere for mange værtskapabiliteter eller dårligt implementerede bindinger kan skabe sikkerhedssårbarheder.
Bedste Praksis:
- Minimer Kald på tværs af Sandboxen: Batch operationer, hvor det er muligt. I stedet for at kalde en værtsfunktion for hvert enkelt element i et stort datasæt, så send hele datasættet på én gang.
- Brug Kørselsmiljøspecifikke Værktøjer: Udnyt værktøjer som
wasm-bindgen(for JavaScript) eller bindingsgenereringsfunktionerne i kørselsmiljøer som Wasmtime og Wasmer for at automatisere marshalling og reducere boilerplate-kode. - Foretræk WASI for Systeminterfaces: Når du interagerer med standard systemfunktionaliteter (fil-I/O, netværk), foretræk WASI-interfaces for bedre portabilitet og standardisering.
- Stærk Typning: Sørg for, at funktionssignaturer mellem WASM og værten er præcist matchet. Brug genererede typesikre bindinger, når det er muligt.
- Omhyggelig Hukommelseshåndtering: Forstå, hvordan WASM lineær hukommelse fungerer. Når du sender data, skal du sikre dig, at de er korrekt kopieret eller delt, og undgå hængende pointers eller adgang uden for grænserne.
- Isoler Upålidelig Kode: Hvis du kører upålidelige WASM-moduler, skal du sikre, at de kun får tildelt de minimalt nødvendige host-bindinger og kører inden for et strengt kontrolleret miljø.
- Ydeevneprofilering: Profilér din applikation for at identificere hot spots i vært-WASM-interaktioner og optimer i overensstemmelse hermed.
Fremtiden for WebAssembly Host-bindinger
Landskabet for WebAssembly er i konstant udvikling. Flere nøgleområder former fremtiden for host-bindinger:
- WebAssembly Component Model: Dette er en betydelig udvikling, der sigter mod at give en mere struktureret og standardiseret måde for WASM-moduler at interagere med hinanden og med værten. Det introducerer koncepter som interfaces og komponenter, hvilket gør bindinger mere deklarative og robuste. Denne model er designet til at være sproguafhængig og fungere på tværs af forskellige kørselsmiljøer.
- WASI Evolution: WASI fortsætter med at modnes, med forslag til nye kapabiliteter og forbedringer af eksisterende. Dette vil yderligere standardisere systeminteraktioner og gøre WASM endnu mere alsidigt for miljøer uden for browseren.
- Forbedrede Værktøjer: Forvent fortsatte fremskridt inden for værktøjer til generering af bindinger, fejlfinding af WASM-applikationer og håndtering af afhængigheder på tværs af WASM- og værtsmiljøer.
- WASM som et Universelt Pluginsystem: Kombinationen af WASM's sandboxing, portabilitet og host-binding-kapabiliteter positionerer det som en ideel løsning til at bygge udvidelige applikationer, hvilket giver udviklere mulighed for let at tilføje nye funktioner eller integrere tredjepartslogik.
Konklusion
WebAssembly host-bindinger er omdrejningspunktet for at frigøre det fulde potentiale af WebAssembly ud over dets oprindelige browserkontekst. De muliggør problemfri kommunikation og dataudveksling mellem WASM-moduler og deres værtsmiljøer, hvilket letter kraftfulde integrationer på tværs af forskellige platforme og sprog. Uanset om du udvikler til web, server-side applikationer, indlejrede systemer eller edge computing, er forståelse og effektiv udnyttelse af host-bindinger nøglen til at bygge ydedygtige, sikre og portable applikationer.
Ved at omfavne bedste praksis, udnytte moderne værktøjer og holde øje med nye standarder som Component Model og WASI, kan udviklere udnytte kraften i WebAssembly til at skabe den næste generation af software, der virkelig gør det muligt for kode at køre overalt, sikkert og effektivt.
Klar til at integrere WebAssembly i dine projekter? Begynd at udforske host-binding-mulighederne i dit valgte kørselsmiljø og sprog i dag!